spacepaste

  1.  
  2. #define F_CPU 8000000UL
  3. #include <avr/io.h>
  4. #include <stdio.h>
  5. #include <inttypes.h>
  6. #include <stdint.h>
  7. #include <avr/pgmspace.h>
  8. #include <avr/interrupt.h>
  9. #include <util/delay.h>
  10. #include <util/atomic.h>
  11. #include <avr/wdt.h>
  12. #define BAUDRATE 9600
  13. #define NTCBETA 3380
  14. #define NTCRES 10000
  15. #define NTCFIXEDRES 10000
  16. #define ONTEMP 4.0 // °C
  17. #define OFFTEMP 2.0 // °C
  18. #define POWERONDELAY 5 // sec
  19. #define ONTIME 60 // sec
  20. #define OFFTIME 180 // sec
  21. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  22. // attiny48 //
  23. // pins //
  24. // 1 : PB5 reset, ADC0 //
  25. // 2 : PB3 ADC3 / RELAY //
  26. // 3 : PB4 ADC2 / CAP //
  27. // 4 : gnd //
  28. // 5 : PB0 Mosi, AREF //
  29. // 6 : PB1 Miso / TX //
  30. // 7 : PB2 SCK, ADC1 / NTC //
  31. // 8 : VCC //
  32. // //
  33. // VCC -> 10k -> NTC -> GND //
  34. // NTC: NTSD1XH103FPB40 https://media.digikey.com/pdf/Data%20Sheets/Murata%20PDFs/NTSD1%20Spec.pdf //
  35. // Beta: 3380 //
  36. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  37. #define RELAYPIN PINB
  38. #define RELAYDDR DDRB
  39. #define RELAYPORT PORTB
  40. #define RELAYBIT 3
  41. #define CAPPIN PINB
  42. #define CAPDDR DDRB
  43. #define CAPPORT PORTB
  44. #define CAPBIT 4
  45. #define NTCPIN PINB
  46. #define NTCPORT PORTB
  47. #define NTCDDR DDRB
  48. #define NTCMUX 1
  49. #define NTCBIT 2
  50. #define UARTTXPIN PINB
  51. #define UARTTXPORT PORTB
  52. #define UARTTXDDR DDRB
  53. #define UARTTXBIT 1
  54. //////////////////////////////////
  55. // Do not edit bellow this line //
  56. //////////////////////////////////
  57. volatile uint32_t timeSecs = 68300;
  58. volatile uint32_t timeCycles = 0;
  59. volatile uint8_t status = 0;
  60. volatile uint16_t timeStatus = 0;
  61. volatile float temperature = 0.0;
  62. void usart_bitdelay() {
  63. _delay_us(1000000/BAUDRATE); // 1e6 us / baudrate
  64. }
  65. void usart_putchar(char data) {
  66. // 0 start, LSB...MSB, 2 stop
  67. uint8_t i;
  68. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  69. // start bit, 0
  70. UARTTXPORT &= ~(1 << UARTTXBIT);
  71. usart_bitdelay();
  72. // 8 data bits
  73. for (i = 8; i != 0; i--) {
  74. if (data & 0x01) {
  75. // 1
  76. UARTTXPORT |= (1 << UARTTXBIT);
  77. } else {
  78. // 0
  79. UARTTXPORT &= ~(1 << UARTTXBIT);
  80. }
  81. data >>= 1;
  82. usart_bitdelay();
  83. }
  84. // stop bit, 1
  85. UARTTXPORT |= (1 << UARTTXBIT);
  86. usart_bitdelay();
  87. usart_bitdelay();
  88. }
  89. }
  90. static FILE mystdout = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE);
  91. void printData() {
  92. uint32_t lsecs;
  93. uint16_t lhours;
  94. uint8_t lmins;
  95. uint8_t lstatus;
  96. uint16_t ltstatus;
  97. float ltemp;
  98. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  99. lsecs = timeSecs;
  100. lstatus = status;
  101. ltstatus = timeStatus;
  102. ltemp = temperature;
  103. };
  104. lhours = lsecs / (uint32_t)3600;
  105. lsecs = lsecs - (lhours * (uint32_t)3600);
  106. lmins = lsecs / (uint32_t)60;
  107. lsecs = lsecs - (lmins * (uint32_t)60);
  108. printf_P(PSTR("% 5u:%02u:%02u "), lhours, lmins, lsecs);
  109. printf_P(PSTR("Temperature: % 6.2f°C Status: %d: "), ltemp, lstatus);
  110. if (lstatus == 0) {
  111. printf_P(PSTR("RCLockout "));
  112. } else if (lstatus == 1) {
  113. printf_P(PSTR("PowerOnDelay"));
  114. } else if (lstatus == 2) {
  115. printf_P(PSTR("Off "));
  116. } else if (lstatus == 3) {
  117. printf_P(PSTR("OffDelay "));
  118. } else if (lstatus == 4) {
  119. printf_P(PSTR("On "));
  120. } else if (lstatus == 5) {
  121. printf_P(PSTR("OnDelay "));
  122. }
  123. printf_P(PSTR(" Since: %5u secs Reset: "), ltstatus);
  124. if (MCUSR & (1<<WDRF)) { printf_P(PSTR("Watchdog")); }
  125. if (MCUSR & (1<<BORF)) { printf_P(PSTR("Brownout")); }
  126. if (MCUSR & (1<<EXTRF)) { printf_P(PSTR("External")); }
  127. if ( ! ((MCUSR & (1<<WDRF)) | (MCUSR & (1<<BORF)) | (MCUSR & (1<<EXTRF)) | (MCUSR & (1<<PORF)))) {
  128. printf_P(PSTR("None"));
  129. }
  130. printf_P(PSTR("\r\n"));
  131. }
  132. void relay(uint8_t state) {
  133. if (state == 0) {
  134. RELAYPORT &= ~(1<<RELAYBIT);
  135. } else if (state == 1) {
  136. RELAYPORT |= (1<<RELAYBIT);
  137. }
  138. }
  139. void calculateTemperature() {
  140. uint16_t adc = 0;
  141. uint8_t loop;
  142. float resistance;
  143. // sample and discard first sample
  144. ADCSRA |= (1<<ADSC);
  145. while (ADCSRA & (1<<ADSC));
  146. // oversample, 16
  147. for (loop = 0; loop < 16; loop++) {
  148. ADCSRA |= (1<<ADSC);
  149. while (ADCSRA & (1<<ADSC));
  150. adc += ADC;
  151. }
  152. // vvv due to oversampling
  153. resistance = ((float)adc * (float)NTCFIXEDRES) / ((1024*16)-adc);
  154. // 1/T0 1 / B R R25 K->C
  155. temperature = 1.0 / ( (1.0/298.15) + (1.0/(float)NTCBETA) * log(resistance / (float)NTCRES) ) - 273.15;
  156. }
  157. int main(void) {
  158. uint32_t ltime = 0;
  159. // set up watchdog timer
  160. wdt_enable(WDTO_8S);
  161. // set relay pin to output, set to off
  162. RELAYDDR |= (1<<RELAYBIT);
  163. relay(0);
  164. // set capacitor pin to input with pullup
  165. CAPDDR &= ~(1<<CAPBIT);
  166. CAPPORT |= (1<<CAPBIT);
  167. // set adc
  168. // attiny85 datasheet recommand 50-200kHz for maximum resolution
  169. // reference of 000 set to VCC, default to 000
  170. // ADMUX |= (1<<REFS0); // external ref
  171. ADMUX |= NTCMUX;
  172. // prescaller /128 = 62.5k@8MHz = 111
  173. ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
  174. // set timer0
  175. TCCR0B |= (1<<CS02) | (1<<CS00); // /1024 prescalling
  176. TIMSK |= (1<<TOIE0); // overflow interrupt enable
  177. // set uart
  178. UARTTXDDR |= (1<<UARTTXBIT);
  179. UARTTXPORT |= (1<<UARTTXBIT);
  180. stdout = &mystdout;
  181. printf_P(PSTR("\r\n"));
  182. printf_P(PSTR("Reset! \r\n"));
  183. // turn on interrupts
  184. sei();
  185. // look if the power reset flag is set, if so reset the reset sources
  186. if (MCUSR & (1<<PORF)) {
  187. MCUSR &= ~((1<<WDRF) | (1<<BORF) | (1<<EXTRF) | (1<<PORF));
  188. }
  189. // Main loop
  190. while(1) {
  191. // wait for a second to pass
  192. while (ltime == timeSecs);
  193. ltime = timeSecs;
  194. calculateTemperature();
  195. if (status == 0) {
  196. // lock out
  197. // check for cap
  198. if (CAPPIN & (1<<CAPBIT)) {
  199. // cap is discharged, release lockout
  200. status = 1;
  201. }
  202. } else if (status == 1) {
  203. // minimum poweron delay
  204. if (timeStatus >= POWERONDELAY) {
  205. status = 2;
  206. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  207. timeStatus = 0;
  208. }
  209. }
  210. } else if (status == 2) {
  211. // Off
  212. relay(0);
  213. if (temperature >= ONTEMP) {
  214. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  215. timeStatus = 0;
  216. }
  217. status = 5;
  218. }
  219. } else if (status == 3) {
  220. // Off with delay
  221. relay(0);
  222. if (timeStatus >= OFFTIME) {
  223. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  224. timeStatus = 0;
  225. }
  226. status = 2;
  227. }
  228. } else if (status == 4) {
  229. // On
  230. relay(1);
  231. if (temperature <= OFFTEMP) {
  232. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  233. timeStatus = 0;
  234. }
  235. status = 3;
  236. }
  237. } else if (status == 5) {
  238. // On with delay
  239. relay(1);
  240. if (timeStatus >= ONTIME) {
  241. ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
  242. timeStatus = 0;
  243. }
  244. status = 4;
  245. }
  246. }
  247. printData();
  248. wdt_reset();
  249. };
  250. return(0);
  251. }
  252. ISR(TIM0_OVF_vect) {
  253. // time keeping
  254. timeCycles += 262144; // 8 bits timer with /1024 prescaller
  255. if (timeCycles >= F_CPU) {
  256. timeCycles -= F_CPU;
  257. timeSecs++;
  258. timeStatus++;
  259. }
  260. }
  261.